package cn.lzm.proxy;

import cn.hutool.core.collection.CollUtil;
import cn.lizemin.constant.RpcConstant;
import cn.lizemin.entity.RpcRequest;
import cn.lizemin.entity.RpcResponse;
import cn.lzm.RpcApplication;
import cn.lzm.config.RpcConfig;
import cn.lzm.fault.retry.RetryStrategy;
import cn.lzm.fault.retry.RetryStrategyFactory;
import cn.lzm.fault.tolerant.TolerantStrategy;
import cn.lzm.fault.tolerant.TolerantStrategyFactory;
import cn.lzm.loadbalancer.LoadBalancerFactory;
import cn.lzm.loadbalancer.LoaderBalancer;
import cn.lzm.model.ServiceMetaInfo;
import cn.lzm.registry.Registry;
import cn.lzm.registry.RegistryFactory;
import cn.lzm.server.tcp.VertxTcpRequestClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;

/**
 * @author lzm
 * @Date 2024/7/21
 * @description JDK动态代理
 */
public class CommonServiceProxy implements InvocationHandler {

    /**
     * 利用动态代理生成请求
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String serviceName = method.getDeclaringClass().getName();
        RpcRequest req = new RpcRequest();
        req.setServiceName(serviceName); // 这个方法在哪个类中
        req.setMethodName(method.getName());
        req.setArgs(args);
        req.setArgTypes(method.getParameterTypes());

        RpcConfig rpcConfig = RpcApplication.getRpcConfig();
        Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getType());
        String serviceKey = getServiceKey(serviceName);
        List<ServiceMetaInfo> metaInfos = registry.discoverService(serviceKey);
        if (CollUtil.isEmpty(metaInfos)) {
            throw new RuntimeException("暂无服务地址");
        }
        LoaderBalancer loaderBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());
        HashMap<String, Object> requestParams = new HashMap<>();
        requestParams.put("methodName", req.getMethodName());
        ServiceMetaInfo serviceMetaInfo = loaderBalancer.select(requestParams, metaInfos);
        // 发送TCP请求
        RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
        RpcResponse response;
        try {
            response = retryStrategy.doRetry(() -> VertxTcpRequestClient.doRequest(serviceMetaInfo, req));
        } catch (Exception e) {
            TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
            response = tolerantStrategy.doTolerant(null, e);
        }
        return response.getData();
    }

    private String getServiceKey(String serviceName) {
        ServiceMetaInfo info = new ServiceMetaInfo();
        info.setName(serviceName);
        info.setVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
        return info.getServiceKey();
    }

}
